//------------------------------------------------------------------------------
// <copyright file="TraceUtility.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//
// <remarks>
// Originally borrowed from the Monad team.
// Ported from base/fs/remotefs/admin/dfsfrs/common/tracer.cs
// Modified Sep 25, 2007 by TLiang and VinPat
// Ported from base/fs/remotefs/admin/wudssui/common/TraceUtility.cs
// Modified by Reputation Services team 2007/2008
// </remarks>
//------------------------------------------------------------------------------
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Text;
using System.Threading;

namespace Microsoft.Reputation.Services
{
    /// <summary>
    /// ExceptionTraceChained
    /// </summary>
    public enum ExceptionTraceChained
    {
        /// <summary>
        /// OuterOnly
        /// </summary>
        OuterOnly,

        /// <summary>
        /// TraceInnermost
        /// </summary>
        TraceInnermost,

        /// <summary>
        /// TraceAllChained
        /// </summary>
        TraceAllChained,
    }

    /// <summary>
    /// Microsoft Storage Management Tracing Utility.
    ///
    /// This class provides additional facilities that are useful for .NET Tracing.
    /// It provides a incremental serial count of trace lines.
    /// It provides a way to provide detailed activity traces that automatically captures
    /// the current stack frame information being traced including method types, method names
    /// and method parameters.
    ///
    /// To use this class please provide a System.Diagnostics.TraceSource object as the 1st argument
    /// when calling any of the static public trace helper methods.  The TraceSource object should have
    /// the appropriate SourceLevels set to allow the appropriate level of traces to be generated.
    ///
    /// Note compilation constant TRACE=1 needs to be defined for this class to perform anything meaningful.
    /// </summary>
    public static class TraceUtility
    {
        private static int m_serialNumber;
        private static string m_processName;
        
        /// <summary>
        /// Allocates some thread local storage to hold the indent level
        /// </summary>
        private static LocalDataStoreSlot s_threadIndentLevel = Thread.AllocateDataSlot();

        #region Constants

        /// <summary>
        ///     The default formatter for TraceError
        /// </summary>
        private const string ErrorFormatter = "ERROR: ";

        /// <summary>
        ///     The default formatter for TraceWarning
        /// </summary>
        private const string WarningFormatter = "Warning: ";

        /// <summary>
        ///     The default formatter for TraceInfo
        /// </summary>
        private const string InfoFormatter = "";

        /// <summary>
        ///     The default formatter for entering TraceConstructor
        /// </summary>
        private const string ConstructorOutputFormatter = "Enter Ctor {0} (this={1})";

        /// <summary>
        ///     The default formatter for leaving TraceConstructor
        /// </summary>
        private const string ConstructorLeavingFormatter = "Leave Ctor {0} (this={1})";

        /// <summary>
        ///     The default formatter for entering TraceDispose
        /// </summary>
        private const string DisposeOutputFormatter = "Enter Disposer {0} (this={1})";
        /// <summary>
        ///     The default formatter for leaving TraceDispose
        /// </summary>
        private const string DisposeLeavingFormatter = "Leave Disposer {0} (this={1})";

        /// <summary>
        ///     The default formatter for entering TraceMethod
        /// </summary>
        private const string MethodOutputFormatter = "Enter {0}: ";

        /// <summary>
        ///     The default formatter for leaving TraceMethod
        /// </summary>
        private const string MethodLeavingFormatter = "Leave {0}";

        /// <summary>
        ///     The default formatter for entering TraceProperty
        /// </summary>
        private const string PropertyOutputFormatter = "Enter property {0}:";
        /// <summary>
        ///     The default formatter for leaving TraceProperty
        /// </summary>
        private const string PropertyLeavingFormatter = "Leave property {0}";

        /// <summary>
        ///     The default formatter for entering TraceDelegateHandler
        /// </summary>
        private const string DelegateHandlerOutputFormatter = "Enter delegate handler: {0}:";
        /// <summary>
        ///     The default formatter for leaving TraceDelegateHandler
        /// </summary>
        private const string DelegateHandlerLeavingFormatter = "Leave delegate handler: {0}";

        /// <summary>
        ///     The default formatter for entering TraceEventHandlers 
        /// </summary>
        private const string EventHandlerOutputFormatter = "Enter event handler: {0}:";
        /// <summary>
        ///     The default formatter for leaving TraceEventHandlers
        /// </summary>
        private const string EventHandlerLeavingFormatter = "Leave event handler: {0}";

        /// <summary>
        ///     The default formatter for TraceException
        /// </summary>
        private const string ExceptionOutputFormatter = "{0}: {1}\r\n{2}";
        /// <summary>
        ///     The default formatter for TraceCatchException
        /// </summary>
        private const string CatchExceptionOutputFormatter = "Caught exception {0}: {1}\r\n{2}";
        /// <summary>
        ///     The default formatter for writing a chained exception
        /// </summary>
        private const string ChainedExceptionOutputFormatter = "\r\nChained {0}: {1}\r\n{2}";
        /// <summary>
        ///     The default formatter for tracing inner-most chained exception
        /// </summary>
        private const string InnermostExceptionOutputFormatter = "\r\nInner-most {0}: {1}\r\n{2}";
        /// <summary>
        ///     The default formatter for TraceThrowException
        /// </summary>
        private const string ThrowingExceptionOutputFormatter = "Throwing exception {0}: {1}";
        /// <summary>
        ///     The default formatter for writing an assertion
        /// </summary>
        private const string DebugAssertOutputFormatter = "ASSERT: {0}\r\n{1}";

        /// <summary>
        ///     The default formatter for entering TraceLock
        /// </summary>
        private const string LockEnterFormatter = "Enter Lock: {0}";
        /// <summary>
        ///     The default formatter for leaving TraceLock
        /// </summary>
        private const string LockLeavingFormatter = "Leave Lock: {0}";
        /// <summary>
        ///     The default formatter for TraceLockAcquiring
        /// </summary>
        private const string LockAcquiringFormatter = "Acquiring Lock: {0}";
        #endregion

        internal enum TraceKind
        {
            Default = 0x00000000,
            Constructor = 0x00000001,
            Dispose = 0x00000002,
            Finalizer = 0x00000004,
            Method = 0x00000008,
            Property = 0x00000010,
            Delegates = 0x00000020,
            Events = 0x00000040,
            Exception = 0x00000080,
            Lock = 0x00000100,
        }

        #region Trace Header

        /// <summary>
        /// Constructor that determines the name of the trace
        /// flag in the config file.
        /// </summary>
        /// <param name="source">Trace Source</param>
        public static void TraceHeader(TraceSource source)
        {
            if (source == null)
            {
                return;
            }

            TraceGlobalAppDomainHeader(source);
            //
            // Use the stack frame to get the calling method's containing class. 
            //
            StackFrame callerFrame = new StackFrame(1);
            MethodBase method = callerFrame.GetMethod();
            Type callingClassType = method.DeclaringType;
            //
            // Trace the object specific tracer information
            //
            TraceObjectHeader(source, callingClassType, callerFrame);
        }

        internal static void TraceGlobalAppDomainHeader(TraceSource source)
        {
            //
            // AppDomain
            //
            OutputLine(source, TraceEventType.Information, TraceKind.Default, "Initializing tracing for AppDomain: {0}", AppDomain.CurrentDomain.FriendlyName);
            //
            // Current time
            //
            OutputLine(source, TraceEventType.Information, TraceKind.Default, "    Current time: {0}", DateTime.Now.ToString("o"));
            //
            // OS build
            //
            OutputLine(source, TraceEventType.Information, TraceKind.Default, "    OS Build: {0}", Environment.OSVersion.VersionString);
            //
            // .NET Framework version
            //
            OutputLine(source, TraceEventType.Information, TraceKind.Default, "    Framework Build: {0}", Environment.Version.ToString());
        }

        internal static void TraceObjectHeader(TraceSource source, Type callingClass, StackFrame callerFrame)
        {
            //
            // Write the header for the new trace object
            //
            OutputLine(source, TraceEventType.Information, TraceKind.Default, "Creating tracer:");
            //
            // Category
            //
            OutputLine(source, TraceEventType.Information, TraceKind.Default, "    Category: {0}", source.Name);

            if (callingClass != null)
            {
                Assembly callingAssembly = callingClass.Assembly;
                //
                // Assembly name
                //
                OutputLine(source, TraceEventType.Information, TraceKind.Default, "    Assembly: {0}", callingAssembly.FullName);
                //
                // Assembly location
                //
                OutputLine(source, TraceEventType.Information, TraceKind.Default, "    Assembly Location: {0}", callingAssembly.Location);
                //
                // Assembly File timestamp
                //
                FileInfo assemblyFileInfo = new FileInfo(callingAssembly.Location);

                OutputLine(source, TraceEventType.Information, TraceKind.Default, "    Assembly File Timestamp: {0}", assemblyFileInfo.CreationTime);
                //
                // Class name
                //
                OutputLine(source, TraceEventType.Information, TraceKind.Default, "    Class: {0}", callingClass.FullName);
            }

            if (callerFrame != null &&
                callerFrame.GetFileName() != null &&
                callerFrame.GetFileName().Length > 0)
            {
                //
                // Line and file if available
                //
                OutputLine(source, TraceEventType.Information, TraceKind.Default, "    At: {0}line: {1:d}", callerFrame.GetFileName(), callerFrame.GetFileLineNumber());
            }

            //
            // Write out the source switch
            //
            if (source.Switch != null)
            {
                OutputLine(
                    source,
                    TraceEventType.Information,
                    TraceKind.Default,
                    string.Format("    Switch: {0} - {1}", source.Switch.DisplayName, source.Switch.Level));
            }
            
        }
        #endregion

        #region Constructors/Destructors
        /// <summary>
        /// Trace in the constructor of an object.
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <returns>
        /// An object that supports IDisposable. The caller
        /// should dispose of the object when it goes out of
        /// scope.
        /// </returns>
        /// <remarks>
        /// The trace will include the object type.
        /// </remarks>
        public static IDisposable TraceConstructor(TraceSource source)
        {
#if TRACE
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.ActivityTracing) != 0)
            {
                return TraceFunctionHelper(
                    source,
                    TraceKind.Constructor,
                    ConstructorOutputFormatter,
                    ConstructorLeavingFormatter,
                    null,
                    null,
                    string.Empty);
            }
#endif
            return null;
        }

        /// <summary>
        /// Trace in the constructor of an object.
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="objBeingConstructed">
        /// The object that is being constructed should be passed. 
        /// This object must support GetHashCode being called
        /// before the object is fully constructed.
        /// </param>
        /// <returns>
        /// An object that supports IDisposable. The caller
        /// should dispose of the object when it goes out of
        /// scope.
        /// </returns>
        /// <remarks>
        /// The trace will include the object type as well as the
        /// result of GetHashCode() such that instances can be
        /// tracked.
        /// </remarks>
        public static IDisposable TraceConstructor(TraceSource source, object objBeingConstructed)
        {
#if TRACE
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.ActivityTracing) != 0)
            {
                return TraceFunctionHelper(
                    source,
                    TraceKind.Constructor,
                    ConstructorOutputFormatter,
                    ConstructorLeavingFormatter,
                    objBeingConstructed,
                    null,
                    string.Empty);
            }
#endif
            return null;
        }

        /// <summary>
        /// Trace in the constructor of an object
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="format">
        /// A format string for additional trace output
        /// </param>
        /// <param name="args">
        /// The additional args for the format string
        /// </param>
        /// <returns>
        /// An object that supports IDisposable. The caller
        /// should dispose of the object when it goes out of
        /// scope.
        /// </returns>
        /// <remarks>
        /// The trace will include the formatted string and
        /// object type.
        /// </remarks>
        public static IDisposable TraceConstructor(TraceSource source, string format, params object[] args)
        {
#if TRACE
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.ActivityTracing) != 0)
            {
                return TraceFunctionHelper(
                    source,
                    TraceKind.Constructor,
                    ConstructorOutputFormatter,
                    ConstructorLeavingFormatter,
                    null,
                    null,
                    format,
                    args);
            }
#endif
            return null;
        }

        /// <summary>
        /// Trace in the constructor of an object
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="objBeingConstructed">
        /// The object that is being constructed should be passed. 
        /// This object must support GetHashCode being called
        /// before the object is fully constructed.
        /// </param>
        /// <param name="format">
        /// A format string for additional trace output
        /// </param>
        /// <param name="args">
        /// The additional args for the format string
        /// </param>
        /// <returns>
        /// An object that supports IDisposable. The caller
        /// should dispose of the object when it goes out of
        /// scope.
        /// </returns>
        /// <remarks>
        /// The trace will include the formatted string,
        /// object type, as well as the result of GetHashCode()
        /// such that instances can be tracked.
        /// </remarks>
        public static IDisposable TraceConstructor(
            TraceSource source,
            object objBeingConstructed,
            string format,
            params object[] args)
        {
#if TRACE
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.ActivityTracing) != 0)
            {
                return TraceFunctionHelper(
                    source,
                    TraceKind.Constructor,
                    ConstructorOutputFormatter,
                    ConstructorLeavingFormatter,
                    objBeingConstructed,
                    null,
                    format,
                    args);
            }
#endif
            return null;
        }

        #endregion

        #region TraceFlags.Dispose methods/helpers
        /// <summary>
        /// Trace in the Dispose method of an object
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <returns>
        /// An object that supports IDisposable. The caller
        /// should dispose of the object when it goes out of
        /// scope.
        /// </returns>
        /// <remarks>
        /// The trace will include the object type and the result
        /// of GetHasCode() such that instances can be tracked.
        /// </remarks>
        public static IDisposable TraceDispose(TraceSource source)
        {
#if TRACE
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.ActivityTracing) != 0)
            {
                return TraceFunctionHelper(
                    source,
                    TraceKind.Dispose,
                    DisposeOutputFormatter,
                    DisposeLeavingFormatter,
                    null,
                    null,
                    string.Empty);
            }
#endif
            return null;
        }

        /// <summary>
        /// Trace in the Dispose method of an object
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="objBeingDisposed">
        /// The object that is getting disposed should be passed.
        /// This object must support GetHashCode being called
        /// during Dispose, keeping in mind that the object might've
        /// already been disposed.
        /// </param>
        /// <returns>
        /// An object that supports IDisposable. The caller
        /// should dispose of the object when it goes out of
        /// scope.
        /// </returns>
        /// <remarks>
        /// The trace will include the object type and the result
        /// of GetHasCode() such that instances can be tracked.
        /// </remarks>
        public static IDisposable TraceDispose(TraceSource source, object objBeingDisposed)
        {
#if TRACE
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.ActivityTracing) != 0)
            {
                return TraceFunctionHelper(
                    source,
                    TraceKind.Dispose,
                    DisposeOutputFormatter,
                    DisposeLeavingFormatter,
                    objBeingDisposed,
                    null,
                    string.Empty);
            }
#endif
            return null;
        }

        /// <summary>
        /// Trace in the Dispose method of an object
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="format">
        /// A format string for additional trace output
        /// </param>
        /// <param name="args">
        /// The additional args for the format string
        /// </param>
        /// <returns>
        /// An object that supports IDisposable. The caller
        /// should dispose of the object when it goes out of
        /// scope.
        /// </returns>
        /// <remarks>
        /// The trace will include the object type and the result
        /// of GetHasCode() such that instances can be tracked.
        /// </remarks>
        public static IDisposable TraceDispose(TraceSource source, string format, params object[] args)
        {
#if TRACE
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.ActivityTracing) != 0)
            {
                return TraceFunctionHelper(
                    source,
                    TraceKind.Dispose,
                    DisposeOutputFormatter,
                    DisposeLeavingFormatter,
                    null,
                    null,
                    format,
                    args);
            }
#endif
            return null;
        }

        /// <summary>
        /// Trace in the Dispose method of an object
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="objBeingDisposed">
        /// The object that is getting disposed should be passed.
        /// This object must support GetHashCode being called
        /// during Dispose, keeping in mind that the object might've
        /// already been disposed.
        /// </param>
        /// <param name="format">
        /// A format string for additional trace output
        /// </param>
        /// <param name="args">
        /// The additional args for the format string
        /// </param>
        /// <returns>
        /// An object that supports IDisposable. The caller
        /// should dispose of the object when it goes out of
        /// scope.
        /// </returns>
        /// <remarks>
        /// The trace will include the object type and the result
        /// of GetHasCode() such that instances can be tracked.
        /// </remarks>
        public static IDisposable TraceDispose(
            TraceSource source,
            object objBeingDisposed,
            string format,
            params object[] args)
        {
#if TRACE
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.ActivityTracing) != 0)
            {
                return TraceFunctionHelper(
                    source,
                    TraceKind.Dispose,
                    DisposeOutputFormatter,
                    DisposeLeavingFormatter,
                    objBeingDisposed,
                    null,
                    format,
                    args);
            }
#endif
            return null;
        }
        #endregion

        #region TraceFlags.Finalizer methods/helpers
        /// <summary>
        /// Trace in the Finalize method of an object
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="objBeingFinalized">
        /// The object that is getting finalized should be passed.
        /// </param>
        /// <remarks>
        /// The trace will include the object type and the result
        /// of GetHasCode() such that instances can be tracked.
        /// </remarks>
        [Conditional("TRACE")]
        public static void TraceFinalizer(TraceSource source, object objBeingFinalized)
        {
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.ActivityTracing) != 0)
            {
                TraceFinalizerHelper(
                    source,
                    objBeingFinalized,
                    string.Empty);
            }
        }

        /// <summary>
        /// Trace in the Finalize method of an object
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="objBeingFinalized">
        /// The object that is getting finalized should be passed.
        /// </param>
        /// <param name="format">
        /// A format string for additional trace output
        /// </param>
        /// <param name="args">
        /// The additional args for the format string
        /// </param>
        /// <remarks>
        /// The trace will include the object type and the result
        /// of GetHasCode() such that instances can be tracked.
        /// </remarks>
        [Conditional("TRACE")]
        public static void TraceFinalizer(TraceSource source, object objBeingFinalized, string format, params object[] args)
        {
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.ActivityTracing) != 0)
            {
                TraceFinalizerHelper(
                    source,
                    objBeingFinalized,
                    format,
                    args);
            }
        }

        /// <summary>
        /// Consolidates the the output formatting from the other
        /// TraceFinalizer methods
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="objBeingFinalized">
        /// The object that is being finalized
        /// </param>
        /// <param name="format">
        /// A format string that is formatted using the args param
        /// </param>
        /// <param name="args">
        /// Additional arguments used in formatting the output
        /// </param>
        [Conditional("TRACE")]
        internal static void TraceFinalizerHelper(TraceSource source, object objBeingFinalized, string format, params object[] args)
        {
            try
            {
                StringBuilder output = new StringBuilder("Finalize: ");

                if (objBeingFinalized != null)
                {
                    //
                    // Format in the object information
                    //
                    output.AppendFormat(
                        CultureInfo.InvariantCulture,
                        "{0}: {1:d}:",
                        objBeingFinalized.GetType(),
                        objBeingFinalized.GetHashCode());
                }
                //
                // Now format in the user specified args
                //
                output.AppendFormat(
                    CultureInfo.InvariantCulture,
                    format,
                    args);
                //
                // Finally trace out the line
                //
                OutputLine(source, TraceEventType.Verbose, TraceKind.Finalizer, output.ToString());
            }
            catch (Exception exception)
            {
                //
                // Eat all exceptions except fatal ones
                //
                if (IsFatalException(exception))
                {
                    throw;
                }
                //
                // Do not assert here because exceptions can be
                // raised while a thread is shutting down during
                // normal operation.
                //
            }
        }
        #endregion

        #region TraceFlags.Method methods/helpers
        /// <summary>
        /// Traces the method name and indents the trace output.
        /// </summary>
        /// <returns>
        /// An object that supports IDisposable. The caller
        /// should dispose of the object when it goes out of
        /// scope.
        /// </returns>
        /// <remarks>
        /// <newpara/>
        /// <example>
        /// <code>
        /// public void MethodName()
        /// {
        ///     using (TraceMethod())
        ///     {
        ///         // do something here...
        ///     }
        /// }
        /// </code>
        /// </example>
        /// <newpara/>
        /// This will produce output similar to the following:
        /// <newpara/>
        /// Entering MethodName:
        ///     other trace output indented
        /// Leaving MethodName
        /// </remarks>
        public static IDisposable TraceMethod(TraceSource source)
        {
#if TRACE
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.ActivityTracing) != 0)
            {
                return TraceFunctionHelper(
                    source,
                    TraceKind.Method,
                    MethodOutputFormatter,
                    MethodLeavingFormatter,
                    null,
                    null,
                    string.Empty);
            }
#endif
            return null;
        }

        /// <summary>
        /// Traces the method name and indents the trace output.
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="callerStackFrame">
        /// Stack frame of the calling function
        /// </param>
        /// <returns>
        /// An object that supports IDisposable. The caller
        /// should dispose of the object when it goes out of
        /// scope.
        /// </returns>
        /// <remarks>
        /// <newpara/>
        /// <example>
        /// <code>
        /// public void MethodName()
        /// {
        ///     using (TraceMethod(new StackFrame(0)))
        ///     {
        ///         // do something here...
        ///     }
        /// }
        /// </code>
        /// </example>
        /// <newpara/>
        /// This will produce output similar to the following:
        /// <newpara/>
        /// Entering MethodName:
        ///     other trace output indented
        /// Leaving MethodName
        /// </remarks>
        public static IDisposable TraceMethod(TraceSource source, StackFrame callerStackFrame)
        {
#if TRACE
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.ActivityTracing) != 0)
            {
                return TraceFunctionHelper(
                    source,
                    TraceKind.Method,
                    MethodOutputFormatter,
                    MethodLeavingFormatter,
                    null,
                    callerStackFrame,
                    string.Empty);
            }
#endif
            return null;
        }

        /// <summary>
        /// Traces the method name and indents the trace output
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="format">
        /// The format string for additional arguments to be traced
        /// </param>
        /// <param name="args">
        /// The additional arguments given to the format string
        /// </param>
        /// <returns>
        /// An object that supports IDisposable. The caller
        /// should dispose of the object when it goes out of
        /// scope.
        /// </returns>
        /// <remarks>
        /// <newpara/>
        /// <example>
        /// <code>
        /// public void MethodName(int count)
        /// {
        ///     using (TraceMethod(
        ///                "count={0:d}",
        ///                count))
        ///     {
        ///         // do something here...
        ///     }
        /// }
        /// </code>
        /// </example>
        /// <newpara/>
        /// This will produce output similar to the following:
        /// <newpara/>
        /// Entering MethodName: count=4
        ///     other trace output indented
        /// Leaving MethodName
        /// </remarks>
        public static IDisposable TraceMethod(TraceSource source, string format, params object[] args)
        {
#if TRACE
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.ActivityTracing) != 0)
            {
                return TraceFunctionHelper(
                    source,
                    TraceKind.Method,
                    MethodOutputFormatter,
                    MethodLeavingFormatter,
                    null,
                    null,
                    format,
                    args);
            }
#endif
            return null;
        }

        /// <summary>
        /// Traces the method name and indents the trace output
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="format">
        /// The format string for additional arguments to be traced
        /// </param>
        /// <param name="args">
        /// The additional arguments given to the format string
        /// </param>
        /// <param name="callerStackFrame">Call stack frame</param>
        /// <returns>
        /// An object that supports IDisposable. The caller
        /// should dispose of the object when it goes out of
        /// scope.
        /// </returns>
        /// <remarks>
        /// <newpara/>
        /// <example>
        /// <code>
        /// public void MethodName(int count)
        /// {
        ///     using (TraceMethod(
        ///                 new StackFrame(0),
        ///                 "count={0:d}",
        ///                 count))
        ///     {
        ///         // do something here...
        ///     }
        /// }
        /// </code>
        /// </example>
        /// <newpara/>
        /// This will produce output similar to the following:
        /// <newpara/>
        /// Entering MethodName: count=4
        ///     other trace output indented
        /// Leaving MethodName
        /// </remarks>
        public static IDisposable TraceMethod(TraceSource source, StackFrame callerStackFrame, string format, params object[] args)
        {
#if TRACE
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.ActivityTracing) != 0)
            {
                return TraceFunctionHelper(
                    source,
                    TraceKind.Method,
                    MethodOutputFormatter,
                    MethodLeavingFormatter,
                    null,
                    callerStackFrame,
                    format,
                    args);
            }
#endif
            return null;
        }

        /// <summary>
        /// Overload of TraceMethod that displays the ToString of the supplied object, or null if the reference is null.
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="obj">object instance</param>
        /// <returns>IDisposable</returns>
        public static IDisposable TraceMethod(TraceSource source, object obj)
        {
#if TRACE
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.ActivityTracing) != 0)
            {
                return TraceFunctionHelper(
                    source,
                    TraceKind.Method,
                    MethodOutputFormatter,
                    MethodLeavingFormatter,
                    null,
                    null,
                    "{0}",
                    (obj == null) ? "null" : obj);
            }
#endif
            return null;
        }

        /// <summary>
        /// Overload of TraceMethod that displays the ToString of the supplied object, or null if the reference is null.
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="callerStackFrame">Caller stack frame</param>
        /// <param name="obj">optional object parameter</param>
        /// <returns>IDisposable</returns>
        public static IDisposable TraceMethod(TraceSource source, StackFrame callerStackFrame, object obj)
        {
#if TRACE
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.ActivityTracing) != 0)
            {
                return TraceFunctionHelper(
                    source,
                    TraceKind.Method,
                    MethodOutputFormatter,
                    MethodLeavingFormatter,
                    null,
                    callerStackFrame,
                    "{0}",
                    (obj == null) ? "null" : obj);
            }
#endif
            return null;
        }
        #endregion

        #region TraceFlags.Property methods/helpers
        /// <summary>
        /// Traces the entrance and exit of a property getter or setter
        /// using the form get_PropertyName or set_PropertyName
        /// </summary>
        /// <returns>
        /// An object that will automatically fix up indentation during
        /// property get/set.
        /// </returns>
        public static IDisposable TraceProperty(TraceSource source)
        {
#if TRACE
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.ActivityTracing) != 0)
            {
                return TraceFunctionHelper(
                    source,
                    TraceKind.Property,
                    PropertyOutputFormatter,
                    PropertyLeavingFormatter,
                    null,
                    null,
                    string.Empty);
            }
#endif
            return null;
        }

        /// <summary>
        /// Traces the entrance and exit of a property getter or setter
        /// using the form get_PropertyName or set_PropertyName
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="format">
        /// A format string used for additional output
        /// </param>
        /// <param name="args">
        /// Additional arguments for the format string
        /// </param>
        /// <returns>
        /// An object that will automatically fix up indentation during
        /// property get/set.
        /// </returns>
        public static IDisposable TraceProperty(TraceSource source, string format, params object[] args)
        {
#if TRACE
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.ActivityTracing) != 0)
            {
                return TraceFunctionHelper(
                    source,
                    TraceKind.Property,
                    PropertyOutputFormatter,
                    PropertyLeavingFormatter,
                    null,
                    null,
                    format,
                    args);
            }
#endif
            return null;
        }

        /// <summary>
        /// Traces the entrance and exit of a property getter or setter
        /// using the form get_PropertyName or set_PropertyName
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="obj">
        /// An object to dump when the trace is emitted. null is permissible.
        /// </param>
        /// <returns>
        /// An object that will automatically fix up indentation during
        /// property get/set.
        /// </returns>
        public static IDisposable TraceProperty(TraceSource source, object obj)
        {
#if TRACE
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.ActivityTracing) != 0)
            {
                return TraceFunctionHelper(
                    source,
                    TraceKind.Property,
                    PropertyOutputFormatter,
                    PropertyLeavingFormatter,
                    null,
                    null,
                    "{0}",
                    (obj == null) ? "null" : obj);
            }
#endif
            return null;
        }
        #endregion

        #region TraceFlags.Delegates methods/helpers

        /// <summary>
        /// Traces the calling of the delegate using the delegate
        /// object to determine the the function type that is being called
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="delegateObj">
        /// The object representing the delegate which is going
        /// to be called.
        /// </param>
        [Conditional("TRACE")]
        public static void TraceDelegate(TraceSource source, object delegateObj)
        {
            TraceFunctionHelper(
                source,
                TraceKind.Delegates,
                DelegateHandlerOutputFormatter,
                DelegateHandlerLeavingFormatter,
                null,
                null,
                string.Empty);
        }

        /// <summary>
        /// Traces the calling of the delegate using the delegate
        /// object to determine the the function type that is being called
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="delegateObj">
        /// The object representing the delegate which is going
        /// to be called.
        /// </param>
        /// <param name="format">
        /// Additional format string to append
        /// </param>
        /// <param name="args">
        /// Arguments to the additional format string
        /// </param>
        [Conditional("TRACE")]
        public static void TraceDelegate(TraceSource source, object delegateObj, string format, params object[] args)
        {
            TraceFunctionHelper(
                source,
                TraceKind.Delegates,
                DelegateHandlerOutputFormatter,
                DelegateHandlerLeavingFormatter,
                null,
                null,
                format,
                args);
        }

        /// <summary>
        /// Helper used from TraceDelegate to format the
        /// parameters for output and write the trace line
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="delegateObj">
        /// The object representing the delegate which is going
        /// to be called.
        /// </param>
        /// <param name="format">
        /// Additional format string to append
        /// </param>
        /// <param name="args">
        /// Arguments to the additional format string
        /// </param>
        [Conditional("TRACE")]
        internal static void TraceDelegateHelper(TraceSource source, object delegateObj, string format, params object[] args)
        {
            try
            {
                //
                // Get the type of the delegate
                //
                Type delegateType = delegateObj.GetType();
                //
                // Format the type and the additional format string together
                //
                StringBuilder output = new StringBuilder("Delegating: ");
                output.AppendFormat(
                    CultureInfo.InvariantCulture,
                    "{0}: ",
                    delegateType.Name);
                output.AppendFormat(
                    CultureInfo.InvariantCulture,
                    format,
                    args);
                //
                // Write the trace
                //
                OutputLine(source, TraceEventType.Verbose, TraceKind.Delegates, output.ToString());
            }
            catch (Exception exception)
            {
                //
                // Eat all exceptions except fatal ones
                //
                if (IsFatalException(exception))
                {
                    throw;
                }
                //
                // Do not assert here because exceptions can be
                // raised while a thread is shutting down during
                // normal operation.
                //
            }
        }

        /// <summary>
        /// Traces the entrance and exit from delegate handlers
        /// </summary>
        /// <returns>
        /// An object that supports IDisposable. The caller
        /// should dispose of the object when it goes out of
        /// scope.
        /// </returns>
        public static IDisposable TraceDelegateHandler(TraceSource source)
        {
#if TRACE
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.ActivityTracing) != 0)
            {
                return TraceFunctionHelper(
                    source,
                    TraceKind.Delegates,
                    DelegateHandlerOutputFormatter,
                    DelegateHandlerLeavingFormatter,
                    null,
                    null,
                    string.Empty);
            }
#endif
            return null;
        }

        /// <summary>
        /// Traces the entrance and exit from delegate handlers
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="format">
        /// The format string for additional arguments to be traced
        /// </param>
        /// <param name="args">
        /// The additional arguments given to the format string
        /// </param>
        /// <returns>
        /// An object that supports IDisposable. The caller
        /// should dispose of the object when it goes out of
        /// scope.
        /// </returns>
        public static IDisposable TraceDelegateHandler(TraceSource source, string format, params object[] args)
        {
#if TRACE
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.ActivityTracing) != 0)
            {
                return TraceFunctionHelper(
                    source,
                    TraceKind.Delegates,
                    DelegateHandlerOutputFormatter,
                    DelegateHandlerLeavingFormatter,
                    null,
                    null,
                    format,
                    args);
            }
#endif
            return null;
        }
        #endregion

        #region TraceFlags.Events methods/helpers
        /// <summary>
        /// Traces the raising of events using the delegate
        /// object to determine the the function type that is being called
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="eventObj">
        /// The object representing the delegate which is going
        /// to be called.
        /// </param>
        [Conditional("TRACE")]
        public static void TraceRaiseEvent(TraceSource source, object eventObj)
        {
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.ActivityTracing) != 0)
            {
                TraceRaiseEventHelper(
                    source,
                    eventObj,
                    string.Empty);
            }
        }

        /// <summary>
        /// Traces the raising of events using the delegate
        /// object to determine the the function type that is being called
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="eventObj">
        /// The object representing the delegate which is going
        /// to be called.
        /// </param>
        /// <param name="format">
        /// Additional format string to append
        /// </param>
        /// <param name="args">
        /// Arguments to the additional format string
        /// </param>
        [Conditional("TRACE")]
        public static void TraceRaiseEvent(TraceSource source, object eventObj, string format, params object[] args)
        {
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.ActivityTracing) != 0)
            {
                TraceRaiseEventHelper(
                    source,
                    eventObj,
                    format,
                    args);
            }
        }

        /// <summary>
        /// Helper used from TraceRaiseEvent to format the
        /// parameters for output and write the trace line
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="eventObj">
        /// The object representing the delegate which is going
        /// to be called.
        /// </param>
        /// <param name="format">
        /// Additional format string to append
        /// </param>
        /// <param name="args">
        /// Arguments to the additional format string
        /// </param>
        [Conditional("TRACE")]
        internal static void TraceRaiseEventHelper(TraceSource source, object eventObj, string format, params object[] args)
        {
            try
            {
                Trace.Assert(format != null, "The format string should not be null");
                //
                // Get the type of the event
                //
                Type eventType = eventObj.GetType();
                //
                // Format the type and the additional format string together
                //
                StringBuilder output = new StringBuilder("Raising Event: ");

                output.AppendFormat(
                    CultureInfo.InvariantCulture,
                    "{0}: ",
                    eventType.Name);

                if (!string.IsNullOrEmpty(format))
                {
                    output.AppendFormat(
                        CultureInfo.InvariantCulture,
                        format,
                        args);
                }
                //
                // Write the trace
                //
                OutputLine(source, TraceEventType.Verbose, TraceKind.Events, output.ToString());
            }
            catch (Exception exception)
            {
                //
                // Eat all exceptions except fatal ones
                //
                if (IsFatalException(exception))
                {
                    throw;
                }
                //
                // Do not assert here because exceptions can be
                // raised while a thread is shutting down during
                // normal operation.
                //
            }
        }

        /// <summary>
        /// Traces the entrance and exit from event handlers
        /// </summary>
        /// <returns>
        /// An object that supports IDisposable. The caller
        /// should dispose of the object when it goes out of
        /// scope.
        /// </returns>
        public static IDisposable TraceEventHandlers(TraceSource source)
        {
#if TRACE
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.ActivityTracing) != 0)
            {
                return TraceFunctionHelper(
                    source,
                    TraceKind.Events,
                    EventHandlerOutputFormatter,
                    EventHandlerLeavingFormatter,
                    null,
                    null,
                    string.Empty);
            }
#endif
            return null;
        }

        /// <summary>
        /// Traces the entrance and exit from event handlers
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="format">
        /// The format string for additional arguments to be traced
        /// </param>
        /// <param name="args">
        /// The additional arguments given to the format string
        /// </param>
        /// <returns>
        /// An object that supports IDisposable. The caller
        /// should dispose of the object when it goes out of
        /// scope.
        /// </returns>
        public static IDisposable TraceEventHandlers(TraceSource source, string format, params object[] args)
        {
#if TRACE
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.ActivityTracing) != 0)
            {
                return TraceFunctionHelper(
                    source,
                    TraceKind.Events,
                    EventHandlerOutputFormatter,
                    EventHandlerLeavingFormatter,
                    null,
                    null,
                    format,
                    args);
            }
#endif
            return null;
        }
        #endregion

        #region TraceFlags.Exception methods/helpers
        /// <summary>
        /// Traces the Message and StackTrace properties of the exception
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="exceptionRecord">
        /// The exception to be traced
        /// </param>
        [Conditional("TRACE")]
        public static void TraceCatchException(TraceSource source, Exception exceptionRecord)
        {
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.Error) != 0)
            {
                WriteException(
                    source,
                    exceptionRecord,
                    ExceptionTraceChained.TraceAllChained,
                    CatchExceptionOutputFormatter);
            }
        }

        /// <summary>
        /// Traces the Message and StackTrace properties of the exception
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="exceptionRecord">
        /// The exception to be traced
        /// </param>
        /// <param name="traceChained">
        /// If true, traces inner-most exception
        /// </param>
        [Conditional("TRACE")]
        public static void TraceCatchException(TraceSource source, Exception exceptionRecord, ExceptionTraceChained traceChained)
        {
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.Error) != 0)
            {
                WriteException(
                    source,
                    exceptionRecord,
                    traceChained,
                    CatchExceptionOutputFormatter);
            }
        }

        /// <summary>
        /// Traces the Message and StackTrace properties of the exception
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="exceptionRecord">
        /// The exception to be traced
        /// </param>
        [Conditional("TRACE")]
        public static void TraceException(TraceSource source, Exception exceptionRecord)
        {
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.Error) != 0)
            {
                WriteException(
                    source,
                    exceptionRecord,
                    ExceptionTraceChained.TraceAllChained,
                    ExceptionOutputFormatter);
            }
        }

        /// <summary>
        /// Traces the Message and StackTrace properties of the exception
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="exceptionRecord">
        /// The exception to be traced
        /// </param>
        /// <param name="traceChained">
        /// If true, traces inner-most exception
        /// </param>
        [Conditional("TRACE")]
        public static void TraceException(TraceSource source, Exception exceptionRecord, ExceptionTraceChained traceChained)
        {
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.Error) != 0)
            {
                WriteException(
                    source,
                    exceptionRecord,
                    traceChained,
                    ExceptionOutputFormatter);
            }
        }

        /// <summary>
        /// Traces the Message and StackTrace properties of the exception
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="exceptionRecord">
        /// The exception to be traced
        /// </param>
        public static void TraceThrowException(TraceSource source, Exception exceptionRecord)
        {
#if TRACE
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.Error) != 0)
            {
                WriteException(
                    source,
                    exceptionRecord,
                    ExceptionTraceChained.TraceAllChained,
                    ThrowingExceptionOutputFormatter);
            }
#endif
            ////
            //// Always throw the exception on behalf of the caller
            ////
            //throw exceptionRecord;
        }

        /// <summary>
        /// Traces the Message and StackTrace properties of the exception
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="exceptionRecord">
        /// The exception to be traced
        /// </param>
        /// <param name="traceChained">
        /// If true, traces inner-most exception
        /// </param>
        public static void TraceThrowException(TraceSource source, Exception exceptionRecord, ExceptionTraceChained traceChained)
        {
#if TRACE
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.Error) != 0)
            {
                WriteException(
                    source,
                    exceptionRecord,
                    traceChained,
                    ThrowingExceptionOutputFormatter);
            }
#endif
            ////
            //// Always throw the exception on behalf of the caller
            ////
            //throw exceptionRecord;
        }

        /// <summary>
        /// Traces the Message and StackTrace properties of the exception
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="exceptionRecord">
        /// The exception to be traced
        /// </param>
        /// <param name="options">
        /// Exception trace options
        /// </param>
        /// <param name="outputFormatter">
        /// The format output for the OmTrace. Usually in the form
        /// "Exception: message\n stacktrace"
        /// </param>
        [Conditional("TRACE")]
        internal static void WriteException(
            TraceSource source,
            Exception exceptionRecord,
            ExceptionTraceChained options,
            string outputFormatter)
        {
            try
            {
                StringBuilder output = new StringBuilder();
                //
                // Format the exception information into the outputFormatter
                //
                output.AppendFormat(
                    CultureInfo.InvariantCulture,
                    outputFormatter,
                    exceptionRecord.GetType().ToString(),
                    exceptionRecord.Message,
                    exceptionRecord.StackTrace);
                //
                // Check if we need to go through the list of chained exceptions
                //
                if ((options & ExceptionTraceChained.TraceInnermost) != 0 ||
                    (options & ExceptionTraceChained.TraceAllChained) != 0)
                {
                    while (exceptionRecord.InnerException != null)
                    {
                        exceptionRecord = exceptionRecord.InnerException;

                        string recordFormat = null;
                        if ((options & ExceptionTraceChained.TraceAllChained) != 0)
                        {
                            recordFormat = ChainedExceptionOutputFormatter;
                        }
                        else if (exceptionRecord.InnerException == null)
                        {
                            recordFormat = InnermostExceptionOutputFormatter;
                        }
                        else
                        {
                            continue;
                        }

                        output.AppendFormat(
                            CultureInfo.InvariantCulture,
                            recordFormat,
                            exceptionRecord.GetType().ToString(),
                            exceptionRecord.Message,
                            exceptionRecord.StackTrace);
                    }
                }

                OutputLine(source, TraceEventType.Error, TraceKind.Exception, output.ToString());
            }
            catch (Exception exception)
            {
                //
                // Eat all exceptions except fatal ones
                //
                if (IsFatalException(exception))
                {
                    throw;
                }
                //
                // Do not assert here because exceptions can be
                // raised while a thread is shutting down during
                // normal operation.
                //
            }
        }
        #endregion

        #region Trace Asserts
        /// <summary>
        /// Trace Asserts
        /// </summary>
        /// <param name="source">Trace source to write to</param>
        /// <param name="condition">Condition to assert</param>
        public static void TraceAssert(TraceSource source, bool condition)
        {
            if (condition == false && !ThreadAborting())
            {
#if TRACE
                if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.Error) != 0)
                {
                    WriteAssert(source, string.Empty);
                }
#endif
                Debug.Assert(condition);
            }
        }

        /// <summary>
        /// Trace Asserts
        /// </summary>
        /// <param name="source">Trace source to write to</param>
        /// <param name="condition">Condition to assert</param>
        /// <param name="message">Message to display when assert condition is false</param>
        public static void TraceAssert(TraceSource source, bool condition, string message)
        {
            if (condition == false && !ThreadAborting())
            {
#if TRACE
                if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.Error) != 0)
                {
                    WriteAssert(source, message);
                }
#endif
                Debug.Assert(condition, message);
            }
        }

        /// <summary>
        /// Trace Asserts
        /// </summary>
        /// <param name="source">Trace source to write to</param>
        /// <param name="condition">Condition to assert</param>
        /// <param name="messageFormat">Message format specification to display when assert condition is false</param>
        /// <param name="args">Arguments for assert message</param>
        public static void TraceAssert(TraceSource source, bool condition, string messageFormat, params object[] args)
        {
            if (condition == false && !ThreadAborting())
            {
                string message = string.Format(CultureInfo.InvariantCulture, messageFormat, args);

#if TRACE
                if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.Error) != 0)
                {
                    WriteAssert(source, message);
                }
#endif
                Debug.Assert(condition, message);
            }
        }

        [Conditional("TRACE")]
        internal static void WriteAssert(TraceSource source, string message)
        {
            try
            {
                //
                // Skip 2 frames here
                //
                OutputLine(source,
                    TraceEventType.Error,
                    TraceKind.Default,
                    DebugAssertOutputFormatter,
                    message,
                    new StackTrace(2).ToString());
            }
            catch (Exception exception)
            {
                //
                // Eat all exceptions except fatal ones
                //
                if (IsFatalException(exception))
                {
                    throw;
                }
                //
                // Do not assert here because exceptions can be
                // raised while a thread is shutting down during
                // normal operation.
                //
            }
        }
        #endregion

        #region TraceFlags.Lock methods/helpers

        /// <summary>
        /// Traces the user specified lock name and indents the trace output.
        /// </summary>
        /// <returns>
        /// An object that supports IDisposable. The caller
        /// should dispose of the object when it goes out of
        /// scope.
        /// </returns>
        /// <remarks>
        /// <newpara/>
        /// <example>
        /// <code>
        /// public void MethodName()
        /// {
        ///     lock (this)
        ///     {
        ///         using (TraceLock("my lock name"))
        ///         {
        ///             // do something here...
        ///         }
        ///     }
        /// }
        /// </code>
        /// </example>
        /// <newpara/>
        /// This will produce output similar to the following:
        /// <newpara/>
        /// Entering Lock: my lock name
        ///     other trace output indented
        /// Leaving Lock: my lock name
        /// </remarks>
        public static IDisposable TraceLock(TraceSource source, string name)
        {
#if TRACE
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.ActivityTracing) != 0)
            {
                try
                {
                    return
                        (IDisposable)
                            new ScopeTracer(
                                source,
                                TraceKind.Lock,
                                LockEnterFormatter,
                                LockLeavingFormatter,
                                name);
                }
                catch (Exception exception)
                {
                    //
                    // Eat all exceptions except fatal ones
                    //
                    if (IsFatalException(exception))
                    {
                        throw;
                    }
                    //
                    // Do not assert here because exceptions can be
                    // raised while a thread is shutting down during
                    // normal operation.
                    //
                }
            }// if: lock flag not off
#endif
            return null;
        }

        /// <summary>
        /// Call this before acquiring a lock
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="name">
        /// User defined name given to the lock
        /// </param>
        [Conditional("TRACE")]
        public static void TraceLockAcquiring(TraceSource source, string name)
        {
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.ActivityTracing) != 0)
            {
                TraceLockHelper(
                    source,
                    LockAcquiringFormatter,
                    name);
            }
        }

        /// <summary>
        /// Call this after acquiring a lock
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="name">
        /// User defined name given to the lock
        /// </param>
        /// <remarks>
        /// Use this only if the TraceLock that returns
        /// an IDisposable won't work in your situation. 
        /// You will not get automatic indentation or 
        /// release tracing of the lock.
        /// </remarks>
        [Conditional("TRACE")]
        public static void TraceLockAcquired(TraceSource source, string name)
        {
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.ActivityTracing) != 0)
            {
                TraceLockHelper(
                    source,
                    LockEnterFormatter,
                    name);
            }
        }

        /// <summary>
        /// Call this after releasing the lock, but only
        /// if you called TraceLockAcquired when you acquired
        /// the lock.
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="name">
        /// User defined name given to the lock
        /// </param>
        [Conditional("TRACE")]
        public static void TraceLockReleased(TraceSource source, string name)
        {
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.ActivityTracing) != 0)
            {
                TraceLockHelper(
                    source,
                    LockLeavingFormatter,
                    name);
            }
        }

        /// <summary>
        /// A helper to simplify tracing of the lock flags.
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="formatter">
        /// A format string for the output.
        /// </param>
        /// <param name="name">
        /// User defined name for the lock
        /// </param>
        [Conditional("TRACE")]
        internal static void TraceLockHelper(TraceSource source, string formatter, string name)
        {
            try
            {
                OutputLine(source, TraceEventType.Verbose, TraceKind.Lock, formatter, name);
            }
            catch (Exception exception)
            {
                //
                // Eat all exceptions except fatal ones
                //
                if (IsFatalException(exception))
                {
                    throw;
                }
                //
                // Do not assert here because exceptions can be
                // raised while a thread is shutting down during
                // normal operation.
                //
            }
        }
        #endregion

        #region TraceFlags.Error,Warning,Normal methods/helpers
        /// <summary>
        /// Traces the specified formatted output when TraceFlags.Error 
        /// is enabled.
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="errorMessageFormat">
        /// The format string containing the error message
        /// </param>
        /// <param name="args">
        /// The arguments for the format string
        /// </param>
        [Conditional("TRACE")]
        public static void TraceError(
            TraceSource source,
            string errorMessageFormat,
            params object[] args)
        {
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.Error) != 0)
            {
                FormatOutputLine(source, TraceEventType.Error, TraceKind.Default, ErrorFormatter, errorMessageFormat, args);
            }
        }

        /// <summary>
        /// Traces the specified formatted output when TraceFlags.Warning 
        /// is enabled.
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="warningMessageFormat">
        /// The format string containing the error message
        /// </param>
        /// <param name="args">
        /// The arguments for the format string
        /// </param>
        [Conditional("TRACE")]
        public static void TraceWarning(
            TraceSource source,
            string warningMessageFormat,
            params object[] args)
        {
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.Warning) != 0)
            {
                FormatOutputLine(source, TraceEventType.Warning, TraceKind.Default, WarningFormatter, warningMessageFormat, args);
            }
        }

        /// <summary>
        /// Traces the formatted output when TraceFlags.TraceInfo is enabled.
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="format">
        /// The format string
        /// </param>
        /// <param name="args">
        /// The arguments for the format string
        /// </param>
        [Conditional("TRACE")]
        public static void TraceInfo(TraceSource source, string format, params object[] args)
        {
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.Information) != 0)
            {
                FormatOutputLine(source, TraceEventType.Information, TraceKind.Default, InfoFormatter, format, args);
            }
        }

        /// <summary>
        /// Traces the formatted output when TraceFlags.TraceInfo is enabled
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="argument">
        /// The object to be output 
        /// </param>
        [Conditional("TRACE")]
        public static void TraceInfo(TraceSource source, object argument)
        {
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.Information) != 0)
            {
                TraceInfo(source, "{0}", argument == null ? "null" : argument);
            }
        }


        /// <summary>
        /// Traces the formatted output when TraceFlags.Debug is enabled.
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="format">
        /// The format string
        /// </param>
        /// <param name="args">
        /// The arguments for the format string
        /// </param>
        [Conditional("TRACE")]
        public static void TraceDebug(TraceSource source, string format, params object[] args)
        {
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.Verbose) != 0)
            {
                FormatOutputLine(source, TraceEventType.Verbose, TraceKind.Default, InfoFormatter, format, args);
            }
        }


        /// <summary>
        /// Traces the formatted output when TraceFlags.Debug is enabled and it is a Debug build.
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="format">
        /// The format string
        /// </param>
        /// <param name="args">
        /// The arguments for the format string
        /// </param>
        [Conditional("DEBUG")]
        public static void TraceDebugOnlyInDebug(TraceSource source, string format, params object[] args)
        {
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.Verbose) != 0)
            {
                FormatOutputLine(source, TraceEventType.Verbose, TraceKind.Default, InfoFormatter, format, args);
            }
        }

        /// <summary>
        /// Traces the formatted output when TraceFlags.Debug is enabled
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="argument">
        /// The object to be output 
        /// </param>
        [Conditional("TRACE")]
        public static void TraceDebug(TraceSource source, object argument)
        {
            if (source != null && source.Switch != null && (source.Switch.Level & SourceLevels.Verbose) != 0)
            {
                TraceDebug(source, "{0}", argument == null ? "null" : argument);
            }
        }

        /// <summary>
        /// Formats the specified text and then traces it
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="eventType">
        /// The type of event
        /// </param>
        /// <param name="kind">
        /// The kind of tracing to be printed in the signature line.
        /// </param>
        /// <param name="classFormatter">
        /// This is the trace class formatter. For instance,
        /// TraceError has a formatter like "ERROR: {0}"
        /// </param>
        /// <param name="format">
        /// Additional format string
        /// </param>
        /// <param name="args">
        /// Arguments for the additional format string
        /// </param>
        [Conditional("TRACE")]
        internal static void FormatOutputLine(TraceSource source, TraceEventType eventType, TraceKind kind, string classFormatter, string format, params object[] args)
        {
            Trace.Assert(format != null, "The format string should not be null");

            try
            {
                //
                // First format the class format string and the
                // user provided format string together
                //
                StringBuilder output = new StringBuilder();

                if (!string.IsNullOrEmpty(classFormatter))
                {
                    output.Append(classFormatter);
                }

                if (!string.IsNullOrEmpty(format))
                {
                    output.AppendFormat(
                        CultureInfo.InvariantCulture,
                        format,
                        args);
                }
                //
                // finally trace the output
                //
                OutputLine(source, eventType, kind, output.ToString());
            }
            catch (Exception exception)
            {
                //
                // Eat all exceptions except fatal ones
                //
                if (IsFatalException(exception))
                {
                    throw;
                }
                //
                // Do not assert here because exceptions can be
                // raised while a thread is shutting down during
                // normal operation.
                //
            }
        }
        #endregion

        #region Class helper methods and properties
        internal static bool ThreadAborting()
        {
            return (Thread.CurrentThread.ThreadState & System.Threading.ThreadState.Aborted) == System.Threading.ThreadState.Aborted ||
                (Thread.CurrentThread.ThreadState & System.Threading.ThreadState.AbortRequested) == System.Threading.ThreadState.AbortRequested;
        }

        /// <summary>
        /// Traces the entrance and exit from method, property, delegate handler, event handler
        /// </summary>
        /// <param name="obj">
        /// Used by TraceDispose and TraceConstructor to trace the 'this' object
        /// </param>
        /// <returns>
        /// An object that supports IDisposable. The caller
        /// should dispose of the object when it goes out of
        /// scope.
        /// </returns>
        internal static IDisposable TraceFunctionHelper(
            TraceSource source,
            TraceKind kind,
            string scopeOutputFormatter,
            string leavingScopeFormatter,
            object obj,
            StackFrame userStackFrame,
            string format,
            params object[] args)
        {
#if TRACE
            try
            {
                string methodName;
                if (userStackFrame == null)
                {
                    //
                    // Get the caller of the outer trace method
                    //
                    methodName = GetCallingMethodNameAndParameters(2);
                }
                else
                {
                    methodName = GetCallingMethodNameAndParameters(userStackFrame);
                }
                //
                // Create the scope tracer object
                //
                return
                    (IDisposable)
                        new ScopeTracer(
                            source,
                            kind,
                            scopeOutputFormatter,
                            leavingScopeFormatter,
                            methodName,
                            obj,
                            format,
                            args);
            }
            catch (Exception exception)
            {
                //
                // Eat all exceptions except fatal ones
                //
                if (IsFatalException(exception))
                {
                    throw;
                }
                //
                // Do not assert here because exceptions can be
                // raised while a thread is shutting down during
                // normal operation.
                //
            }
#endif
            return null;
        }

        /// <summary>
        /// Gets the method name of the method that called this one
        /// plus the skipFrames.
        /// </summary>
        /// <remarks>
        /// For instance, GetCallingMethodNameAndParameters(1) 
        /// will return the method that called the method that is calling
        /// GetCallingMethodNameAndParameters.
        /// </remarks>
        /// <param name="stackFrame">
        /// Stack frame on the callstack
        /// </param>
        /// <returns>
        /// The name of the method on the stack
        /// </returns>
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static string GetCallingMethodNameAndParameters(StackFrame stackFrame)
        {
#if TRACE
            StringBuilder methodAndParameters = null;
            try
            {
                //
                // Use the stack to get the method and type information
                // for the calling method
                //
                MethodBase callingMethod = stackFrame.GetMethod();

                Type declaringType = callingMethod.DeclaringType;
                //
                // Append the class name and method name together
                //
                methodAndParameters = new StringBuilder();
                //
                // Note: don't use the FullName for the declaringType
                // as it is usually way too long and makes the trace
                // output hard to read.
                //
                methodAndParameters.AppendFormat(
                    CultureInfo.InvariantCulture,
                    "{0}.{1}(",
                    declaringType.Name,
                    callingMethod.Name);

                bool notFirst = false;
                //
                // print signature
                //
                ParameterInfo[] parameters = callingMethod.GetParameters();
                foreach (ParameterInfo parameter in parameters)
                {
                    if (notFirst)
                    {
                        //
                        // commas between parameters
                        //
                        methodAndParameters.Append(", ");
                    }
                    else
                    {
                        notFirst = true;
                    }

                    methodAndParameters.Append(parameter.ParameterType.Name);
                }

                methodAndParameters.Append(")");
                ////
                //// Now try to get the parameters
                ////
                //RuntimeMethodHandle runtimeMethod = callingMethod.MethodHandle;
                //
                //BinaryFormatter formatter = new BinaryFormatter();
                //SerializationInfo info = 
                //    new SerializationInfo(
                //        runtimeMethod.GetType(), 
                //        (IFormatterConverter)formatter);
                //
                //runtimeMethod.GetObjectData(info, null);
            }
            catch (Exception exception)
            {
                //
                // Eat all exceptions except fatal ones
                //
                if (IsFatalException(exception))
                {
                    throw;
                }
                //
                // Do not assert here because exceptions can be
                // raised while a thread is shutting down during
                // normal operation.
                //
            }
            return methodAndParameters.ToString();
#else
            return string.Empty;
#endif
        }

        /// <summary>
        /// Gets the method name of the method that called this one
        /// plus the skipFrames.
        /// </summary>
        /// <remarks>
        /// For instance, GetCallingMethodNameAndParameters(1) 
        /// will return the method that called the method that is calling
        /// GetCallingMethodNameAndParameters.
        /// </remarks>
        /// <param name="skipFrames">
        /// The number of frames to skip in the calling stack
        /// </param>
        /// <returns>
        /// The name of the method on the stack
        /// </returns>
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static string GetCallingMethodNameAndParameters(int skipFrames)
        {
#if TRACE
            try
            {
                //
                // Use the stack to get the method and type information
                // for the calling method
                //
                StackFrame stackFrame = new StackFrame(skipFrames + 1);

                return GetCallingMethodNameAndParameters(stackFrame);
            }
            catch (Exception exception)
            {
                //
                // Eat all exceptions except fatal ones
                //
                if (IsFatalException(exception))
                {
                    throw;
                }
                //
                // Do not assert here because exceptions can be
                // raised while a thread is shutting down during
                // normal operation.
                //
            }
#endif
            return string.Empty;
        }

        internal static StringBuilder GetLinePrefix(TraceEventType eventType, TraceKind kind)
        {
#if TRACE
            StringBuilder prefixBuilder = new StringBuilder();
            //
            // TODO: make it configurable and the turn this back on, because it can be sometimes useful in debugging
            //
            ////
            //// Add the process name (it includes id as well - should we split it?)
            ////
            //prefixBuilder.AppendFormat(
            //    CultureInfo.InvariantCulture,
            //    "|{0,-25}",
            //    ProcessName);
            ////
            //// Add the level of the trace.
            ////
            //prefixBuilder.AppendFormat(
            //    CultureInfo.InvariantCulture,
            //    "|{0,-11}",
            //    eventType);
            ////
            //// Add the kind of the trace.
            ////
            //prefixBuilder.AppendFormat(
            //    CultureInfo.InvariantCulture,
            //    "|{0,-11}|",
            //    kind);

            //
            // Add the time stamp
            //
            prefixBuilder.Append(DateTime.Now.ToString("o"));

            //
            // Add the thread ID
            //
            prefixBuilder.AppendFormat(
                CultureInfo.InvariantCulture,
                "|{0:X4}",
                Thread.CurrentThread.ManagedThreadId);

            return prefixBuilder;
#else
            return null;
#endif
        }

        [Conditional("TRACE")]
        internal static void AddTab(ref StringBuilder lineBuilder)
        {
            //
            // The Trace.IndentSize does not change at all
            // through the running of the process so there
            // are no thread issues here.
            //            
            int repeatCount = Trace.IndentSize * ThreadIndentLevel;

            if (repeatCount > 0)
            {
                lineBuilder.Append(' ', repeatCount);
            }
        }

        /// <summary>
        /// Composes a line of trace output and then writes it.
        /// </summary>
        /// <param name="source">Trace source</param>
        /// <param name="eventType">
        /// The type of event
        /// </param>
        /// <param name="kind">
        /// The level that caused the line to be traced
        /// </param>
        /// <param name="format">
        /// The string to write with format symbols if necessary
        /// </param>
        /// <param name="args">
        /// Arguments to the format string
        /// </param>
        /// <remarks>
        /// The line is composed by prefixing the process name, thread ID,
        /// and tick count. Then the indenting is added. Then the
        /// specified string is formatted. Finally the finished string
        /// is output using the Trace class.
        /// </remarks>
        [Conditional("TRACE")]
        internal static void OutputLine(
            TraceSource source,
            TraceEventType eventType,
            TraceKind kind,
            string format,
            params object[] args)
        {
            Trace.Assert(format != null, "The format string should not be null");
            //
            // Get the line prefix string which includes things
            // like App name, clock tick, thread ID, etc.
            //
            StringBuilder lineBuilder = GetLinePrefix(eventType, kind);
            //
            // Add the spaces for the indent
            //
            AddTab(ref lineBuilder);

            if (args != null && args.Length > 0)
            {
                lineBuilder.AppendFormat(
                    CultureInfo.InvariantCulture,
                    format,
                    args);
            }
            else
            {
                lineBuilder.Append(format);
            }

            try
            {
                source.TraceEvent(eventType, Interlocked.Increment(ref m_serialNumber), lineBuilder.ToString());
            }
            catch (Exception ex)
            {
                if (IsFatalException(ex))
                {
                    throw;
                }
                //
                // we could not write the trace statement to the listener, disable all tracing
                //
                DisableTracing(source);
            }
        }

        /// <summary>
        /// Disables all tracing
        /// </summary>
        internal static void DisableTracing(TraceSource source)
        {
            if (source != null && source.Switch != null)
            {
                source.Switch.Level = SourceLevels.Off;
            }
        }

        /// <summary>
        /// Property to access the indent level in thread local storage.
        /// </summary>
        internal static int ThreadIndentLevel
        {
            get
            {
#if TRACE
                object threadLocalStorageObject = Thread.GetData(s_threadIndentLevel);
                //
                // The first time GetData is called the data will be null
                // So prime it with zero
                //
                if (threadLocalStorageObject == null)
                {
                    int initializingValue = 0;

                    Thread.SetData(s_threadIndentLevel, initializingValue);

                    threadLocalStorageObject = Thread.GetData(s_threadIndentLevel);
                }
                //
                // TODO: remove this unboxing (make thread storage class - MRS PS DB #474)
                //
                return (int)threadLocalStorageObject;
#else
                return 0;
#endif
            }

            set
            {
#if TRACE
                if (value >= 0)
                {
                    //
                    // Set the new indent level in thread local storage
                    // TODO: (create a class to avoid boxing MRS PS DB #474)
                    //
                    Thread.SetData(s_threadIndentLevel, value);
                }
                else
                {
                    Trace.Assert(value >= 0, "The indention value cannot be less than zero");
                }
#endif
            }
        }

        /// <summary>
        /// Accessor to a cached copy of the process name 
        /// </summary>
        internal static string ProcessName
        {
            get
            {
#if TRACE
                if (string.IsNullOrEmpty(m_processName))
                {
                    Process currentProcess = Process.GetCurrentProcess();
                    m_processName = string.Format(
                        CultureInfo.InvariantCulture,
                        "{0:X4}|{1}",
                        currentProcess.Id,
                        currentProcess.ProcessName);
                }
#endif
                return m_processName;
            }
        }

        /// <summary>
        /// This method re-throws exceptions an application cannot recover
        /// after
        /// </summary>
        /// <param name="exception"></param>
        static internal bool IsFatalException(Exception exception)
        {
            return (exception is OutOfMemoryException ||
                 exception is StackOverflowException ||
                 exception is ExecutionEngineException);
        }
        #endregion

        #region ScopeTracer object/helpers
        /// <summary>
        ///     A light-weight object to manage the indentation of
        ///     trace output for each thread.
        /// </summary>
        /// <remarks>
        ///     An instance of this object is returned when any scoping
        ///     Trace method (like TraceMethod, TraceProperty, etc.)
        ///     is called. In the constructor to the object the indentation
        ///     level for the thread is incremented and the OmTrace.IndentLevel
        ///     is set to the indentation level for this thread.
        ///     The Dispose method will decrement the thread indent level
        ///     and set the OmTrace.IndentLevel to the new level for this thread.
        /// <newpara/>
        ///     This object should only be constructed by one of the
        ///     scope tracing methods (like TraceMethod, TraceProperty, etc.)
        /// </remarks>
        [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")]
        private class ScopeTracer : IDisposable
        {
            /// <summary>
            ///     The trace object that is used for any output 
            /// </summary>
            private TraceSource m_source;

            /// <summary>
            ///     The flag which caused this scope object to be created.
            /// </summary>
            private TraceKind m_kind;

            /// <summary>
            ///     Stores the scope name that is passed to the constructor.
            /// </summary>
            private string m_scopeName;

            /// <summary>
            ///     Stores the format string used when formatting output when
            ///     leaving the scope
            /// </summary>
            private string m_leavingScopeFormatter;

            /// <summary>
            ///     The object being constructed or disposed. Optionally used by
            ///     TraceConstructor and TraceDispose.
            /// </summary>
            private object m_obj;

            /// <summary>
            ///     Constructor that traces the scope name
            ///     and raises the indent level in thread
            ///     local storage.
            /// </summary>
            /// <param name="tracer">
            ///     The trace object that is to be used for output
            /// </param>
            /// <param name="flag">
            ///     The TraceFlag that is causing the scope object to 
            ///     be created.
            /// </param>
            /// <param name="scopeOutputFormatter">
            ///     This format string is used to determine the
            ///     general output format for the scope. For instance,
            ///     TraceMethod would probably provide a formatter similar
            ///     to "Entering: {0}: {1}" where {0}is the name of the
            ///     method and {1}is the additional formatted info provided.
            /// </param>
            /// <param name="leavingScopeFormatter">
            ///     The format string used to determine the general output
            ///     format for the scope when the Dispose method is called.
            /// </param>
            /// <param name="scopeName">
            ///     The name of the scope that is being traced
            /// </param>
            public ScopeTracer(
                TraceSource source,
                TraceKind kind,
                string scopeOutputFormatter,
                string leavingScopeFormatter,
                string scopeName)
            {
                this.m_source = source;

                // Call the helper
                ScopeTracerHelper(
                    kind,
                    scopeOutputFormatter,
                    leavingScopeFormatter,
                    scopeName,
                    null,
                    string.Empty);
            }

            /// <summary>
            ///     Constructor that traces the scope name
            ///     and raises the indent level in thread
            ///     local storage.
            /// </summary>
            /// 
            /// <param name="tracer">
            ///     The trace object that is to be used for output
            /// </param>
            /// 
            /// <param name="flag">
            ///     The TraceFlag that is causing the scope object to 
            ///     be created.
            /// </param>
            /// 
            /// <param name="scopeOutputFormatter">
            ///     This format string is used to determine the
            ///     general output format for the scope. For instance,
            ///     TraceMethod would probably provide a formatter similar
            ///     to "Entering: {0}: {1}" where {0}is the name of the
            ///     method and {1}is the additional formatted info provided.
            /// </param>
            /// 
            /// <param name="leavingScopeFormatter">
            ///     The format string used to determine the general output
            ///     format for the scope when the Dispose method is called.
            /// </param>
            /// 
            /// <param name="scopeName">
            ///     The name of the scope that is being traced
            /// </param>
            /// 
            /// <param name="format">
            ///     The format of any additional arguments which will be appended
            ///     to the line of trace output
            /// </param>
            /// 
            /// <param name="args">
            ///     Arguments to the format string.
            /// </param>
            public ScopeTracer(
                TraceSource source,
                TraceKind kind,
                string scopeOutputFormatter,
                string leavingScopeFormatter,
                string scopeName,
                object obj,
                string format,
                params object[] args)
            {
                this.m_source = source;
                //
                // Call the helper
                //
                if (!string.IsNullOrEmpty(format))
                {
                    ScopeTracerHelper(
                        kind,
                        scopeOutputFormatter,
                        leavingScopeFormatter,
                        scopeName,
                        obj,
                        format,
                        args);
                }
                else
                {
                    ScopeTracerHelper(
                        kind,
                        scopeOutputFormatter,
                        leavingScopeFormatter,
                        scopeName,
                        obj,
                        string.Empty);
                }
            }

            /// <summary>
            ///     Decrements the indent level in thread local
            ///     storage and then traces the scope name.
            /// </summary>
            public void Dispose()
            {
                //
                // Decrement the indent level in thread local storage
                //
                ThreadIndentLevel--;
                //
                // Trace out the scope name
                //
                OutputLine(
                    m_source,
                    TraceEventType.Stop,
                    m_kind,
                    m_leavingScopeFormatter,
                    m_scopeName,
                    m_obj == null ? string.Empty : m_obj.GetHashCode().ToString(CultureInfo.InvariantCulture));
            }

            /// <summary>
            ///     Helper for the ScopeTracer constructor.
            /// </summary>
            /// 
            /// <param name="flag">
            ///     The flag that caused this line of tracing to be traced.
            /// </param>
            /// 
            /// <param name="scopeOutputFormatter">
            ///     This format string is used to determine the
            ///     general output format for the scope. For instance,
            ///     TraceMethod would probably provide a formatter similar
            ///     to "Entering: {0}: {1}" where {0}is the name of the
            ///     method and {1}is the additional formatted info provided.
            /// </param>
            /// 
            /// <param name="leavingScopeFormatter">
            ///     The format string used to determine the general output
            ///     format for the scope when the Dispose method is called.
            /// </param>
            /// 
            /// <param name="scopeName">
            ///     The name of the scope being entered
            /// </param>
            /// 
            /// <param name="format">
            ///     The format of any additional arguments which will be appended
            ///     to the "Entering" line of trace output
            /// </param>
            /// 
            /// <param name="args">
            ///     Arguments to the format string.
            /// </param>
            private void ScopeTracerHelper(
                TraceKind kind,
                string scopeOutputFormatter,
                string leavingScopeFormatter,
                string scopeName,
                object obj,
                string format,
                params object[] args)
            {
                //
                // Store the flags, scopeName, and the leavingScopeFormatter
                // so that it can be used in the Dispose method
                //
                this.m_kind = kind;
                this.m_scopeName = scopeName;
                this.m_leavingScopeFormatter = leavingScopeFormatter;
                this.m_obj = obj;
                //
                // Format the string for output
                //
                StringBuilder output = new StringBuilder();

                output.AppendFormat(
                    CultureInfo.InvariantCulture,
                    scopeOutputFormatter,
                    scopeName,
                    obj == null ? string.Empty : obj.GetHashCode().ToString(CultureInfo.InvariantCulture));

                output.AppendFormat(
                    CultureInfo.InvariantCulture,
                    format,
                    args);
                //
                // Now write the trace
                //
                OutputLine(m_source, TraceEventType.Start, m_kind, output.ToString());
                //
                // Increment the current thread indent level
                //
                ThreadIndentLevel++;
            }
        }
        #endregion
    }
}
